#include "ModbusClient.h"
#include <QDebug>
#include <FloraLogger.h>
#include <QElapsedTimer>
#define DEVICE_DEBUG

ModbusClient::ModbusClient(QObject *parent)
    : QThread(parent), ctx(nullptr) {}

ModbusClient::~ModbusClient() {
    stopPolling();
    if (ctx) {
        modbus_close(ctx);
        modbus_free(ctx);
    }
}

bool ModbusClient::init(ModbusMode mode, const QString &addressOrPort, int baudOrPort) {
    stopPolling();
    if (ctx) {
        modbus_close(ctx);
        modbus_free(ctx);
        ctx = nullptr;
    }

    this->mode = mode;
    LOG_DEBUG << "modbus start" << mode << addressOrPort << baudOrPort;

    if (mode == RTU)
        ctx = modbus_new_rtu(addressOrPort.toStdString().c_str(), baudOrPort, 'N', 8, 1);
    else
        ctx = modbus_new_tcp(addressOrPort.toStdString().c_str(), baudOrPort);

    if (!ctx) {
        emit errorOccurred("Failed to create Modbus context");
        LOG_ERROR("Failed to create Modbus context");
        return false;
    }

    modbus_set_response_timeout(ctx, 1, 0);

    if (mode == RTU) {
        modbus_set_slave(ctx, 1);
    }
    if(m_enableDebug){
        modbus_set_debug(ctx,true);
    }
    if (modbus_connect(ctx) != 0) {
        QString errStr = QString::fromLocal8Bit(strerror(errno));
        emit errorOccurred("Modbus connection failed: " + errStr);
        LOG_ERROR( QString("Modbus connection failed: %1").arg(strerror(errno)));
        modbus_free(ctx);
        ctx = nullptr;
        return false;
    }

    LOG_DEBUG << "Modbus start success" << addressOrPort << baudOrPort;
    thread_run_flag = true;
    start();
    return true;
}

void ModbusClient::run() {
    uint8_t request_count = 0;
    ModbusRequest temp_modbusRequest;
    QElapsedTimer m_timer;
    int request_amount =0;
    int rec = 0;
    m_timer.start();
    while (thread_run_flag) {
        ModbusRequest temp_command={0};
        temp_command.opType = NONE_OP;
        QMutexLocker locker(&mutex);
        // 优先处理命令队列中的命令
        if (!commandQueue.isEmpty()) {
            temp_command = commandQueue.dequeue();
        }
        locker.unlock();
        int retryCount =3;
        for(int i=0; i<retryCount;i++)
        {
            if(temp_command.opType != NONE_OP)
            {
                switch(temp_command.opType)
                {
                case WriteRegisters:
                    modbus_set_slave(ctx,temp_command.device_id);
                    rec = modbus_write_registers(ctx,temp_command.address,temp_command.length,temp_command.date);
                    break;
                case WriteCoil:
                    modbus_set_slave(ctx,temp_command.device_id);
                    rec = modbus_write_bit(ctx,temp_command.address,temp_command.date_8[0]);
                    break;
                case WriteCoils:
                    modbus_set_slave(ctx,temp_command.device_id);
                    rec = modbus_write_bits(ctx,temp_command.address,temp_command.length,temp_command.date_8);
                    break;
                case ReadCoils:
                    modbus_set_slave(ctx,temp_command.device_id);
                    rec = modbus_read_bits(ctx,temp_command.address,temp_command.length,temp_command.date_8);
                    break;
                case ReadRegisters:
                    modbus_set_slave(ctx,temp_command.device_id);
                    rec = modbus_read_registers(ctx,temp_command.address,temp_command.length,temp_command.date);
                    break;
                }
                if(rec <= 0)
                {
                    temp_command.opResult = false;
                    if(m_enableDebug){
                        LOG_DEBUG<<"写失败 ID："<<temp_command.device_id<<"地址："<<temp_command.address;
                    }
                    if(i == retryCount - 1){
                        emit request_receive_data(temp_command);
                    }
                }
                else
                {

                    temp_command.opResult = true ;
                    if(m_enableDebug) {LOG_DEBUG<<"写成功"<<temp_command.device_id<<"地址："<<temp_command.address;}
                    emit request_receive_data(temp_command);
                    break;

                }

                msleep(2);
            }
        }


        //请求队列
        mutex.lock();
        if(request_count >= requests.size() )
        {
            request_count = 0;
        }
        if(requests.size() >0)
        {
            temp_modbusRequest = requests[request_count];
            if(m_timer.elapsed() - temp_modbusRequest.start_tick > temp_modbusRequest.asktime){
                request_amount = requests.size();
                requests[request_count].start_tick = m_timer.elapsed();
            }else
            {
                request_amount  = 0;
            }
            request_count ++;
        }
        else
        {
            request_amount = 0;
        }
        mutex.unlock();
        if(request_amount >0)
        {
           switch(temp_modbusRequest.opType)
            {
            case WriteRegisters:
                modbus_set_slave(ctx,temp_modbusRequest.device_id);
                rec = modbus_write_registers(ctx,temp_modbusRequest.address,temp_modbusRequest.length,temp_modbusRequest.date);
                break;
            case WriteCoil:
                modbus_set_slave(ctx,temp_modbusRequest.device_id);
                rec = modbus_write_bit(ctx,temp_modbusRequest.address,temp_modbusRequest.date_8[0]);
                break;
            case WriteCoils:
                modbus_set_slave(ctx,temp_modbusRequest.device_id);
                rec = modbus_write_bits(ctx,temp_modbusRequest.address,temp_modbusRequest.length,temp_modbusRequest.date_8);
                break;
            case ReadCoils:
                modbus_set_slave(ctx,temp_modbusRequest.device_id);
                rec = modbus_read_bits(ctx,temp_modbusRequest.address,temp_modbusRequest.length,temp_modbusRequest.date_8);
                break;
            case ReadRegisters:
                modbus_set_slave(ctx,temp_modbusRequest.device_id);
                rec = modbus_read_registers(ctx,temp_modbusRequest.address,temp_modbusRequest.length,temp_modbusRequest.date);
                break;
            }
            if(rec <= 0)
            {
                temp_modbusRequest.opResult = false;
                LOG_DEBUG<<"写失败";
            }
            else
            {
                temp_modbusRequest.opResult = true ;
                LOG_DEBUG<<"写成功";
            }
            emit request_receive_data(temp_modbusRequest);
            msleep(2);
        }
    }
}

void ModbusClient::stopPolling() {
    thread_run_flag = false;
    mutex.lock();
    quit();  // 停止线程
    mutex.unlock();

    wait();  // 等待线程结束
}

void ModbusClient::sendCommand(const ModbusRequest &request) {
    QMutexLocker locker(&mutex);
    commandQueue.enqueue(request);  // 将命令添加到命令队列中
    //commandCondition.wakeOne();  // 唤醒线程处理命令
}

void ModbusClient::sendTestComand()
{

}
bool isSameRequest(const ModbusRequest &a, const ModbusRequest &b)
{
    return
        a.device_id == b.device_id &&
        a.length == b.length &&
        memcmp(a.date_8, b.date_8, sizeof(a.date_8)) == 0 &&
        a.address == b.address &&
        memcmp(a.date, b.date, sizeof(a.date)) == 0 &&
        a.cmdType == b.cmdType &&
        a.asktime == b.asktime &&
        a.opType == b.opType;
}
void ModbusClient::addRequest( ModbusRequest &request) {
    bool exists = false;
    if(request.cmdType == 0){
        QMutexLocker locker(&mutex);
        commandQueue.append(request);
    }
    else if(request.cmdType == 1){
        for (int i = 0; i < requests.size(); ++i) {
           if (isSameRequest(requests[i], request)) {
               exists = true;
               break;
           }
        }

        if (!exists) {
            QMutexLocker locker(&mutex);
            LOG_DEBUG<<"requests.append"<<request.device_id<<request.address;
            requests.append(request);
        }
    }
}

void ModbusClient::setWaitTimeOut(uint32_t ms)
{
    if(ctx){
        modbus_set_response_timeout(ctx, 0, (uint32_t)ms*1000);
    }
}
